package com.yzc.android.ui;

import android.content.Context;
import android.content.Intent;

import com.yzc.android.KDApp;
import com.yzc.android.beans.MotionDeltaBean;
import com.yzc.android.manager.SensorDataListener;
import com.yzc.android.manager.sensor.ESException;
import com.yzc.android.manager.sensor.ESSensorManager;
import com.yzc.android.manager.sensor.SensorConstant;
import com.yzc.android.manager.sensor.data.SensorData;
import com.yzc.android.manager.sensor.dataformatter.DataFormatter;
import com.yzc.android.manager.sensor.dataformatter.json.pull.AccelerometerFormatter;
import com.yzc.android.manager.sensor.dataformatter.json.pull.GyroscopeFormatter;
import com.yzc.android.manager.sensor.dataformatter.json.pull.MagneticFieldFormatter;
import com.yzc.android.manager.sensor.dataformatter.json.pull.StepCounterFormatter;
import com.yzc.android.manager.sensor.dataformatter.json.push.PassiveLocationFormatter;
import com.yzc.android.manager.sensor.dataformatter.json.push.ProximityFormatter;
import com.yzc.android.manager.sensor.sensors.SensorUtils;
import com.yzc.android.utils.LogUtils;
import com.yzc.android.utils.ToastUtil;
import org.json.JSONArray;
import org.json.JSONObject;

/**
 * Created by yzc on 16/5/20.
 */
public class SensorsThread extends Thread implements SensorDataListener {
    private final int sensorType;

    private final Context mContext;

    private final ESSensorManager sensorManager;

    private int subscriptionId;

    private boolean stop = true;

    public SensorsThread(final Context resultScreen, final ESSensorManager sensorManager, int sensorType) {
        this.sensorType = sensorType;
        this.mContext = resultScreen;
        this.sensorManager = sensorManager;
    }

    public void startSensing() {
        try {
            if (!stop) return;
            stop = false;
            subscriptionId = sensorManager.subscribeToSensorData(sensorType, this);
            start();
        }
        catch (Exception e) {
            ToastUtil.getInstance().showToast(e.getLocalizedMessage());
        }
    }

    public void stopSensing() {
        try {
            if (stop) return;
            stop = true;
            sensorManager.unsubscribeFromSensorData(subscriptionId);
        } catch (ESException e) {
            ToastUtil.getInstance().showToast(e.getLocalizedMessage());
        }
    }

    @Override
    public void onDataSensed(SensorData data) {
        try {
            if (stop) return;
            if (sensorType == SensorUtils.SENSOR_TYPE_ACCELEROMETER) {
                if (data != null) {
                    try {
                        AccelerometerFormatter formatter = (AccelerometerFormatter) DataFormatter.getJSONFormatter(mContext, SensorUtils.SENSOR_TYPE_ACCELEROMETER);
                        if (formatter != null) {
                            String jsonData = formatter.toString(data);

                            String content = String.format("%1s\n\n", jsonData);
                            LogUtils.local(SensorConstant.kAccelerometerLogTag, content);

                            JSONObject jsonObject = new JSONObject(jsonData);
                            JSONArray xAxis = jsonObject.optJSONArray("xAxis");
                            JSONArray yAxis = jsonObject.optJSONArray("yAxis");
                            JSONArray zAxis = jsonObject.optJSONArray("zAxis");
                            double[] xAxisData = new double[xAxis.length()];
                            for (int i = 0; i < xAxis.length(); i++) {
                                xAxisData[i] = xAxis.optDouble(i);
                            }

                            double[] yAxisData = new double[yAxis.length()];
                            for (int i = 0; i < yAxis.length(); i++) {
                                yAxisData[i] = yAxis.optDouble(i);
                            }

                            double[] zAxisData = new double[zAxis.length()];
                            for (int i = 0; i < zAxis.length(); i++) {
                                zAxisData[i] = zAxis.optDouble(i);
                            }

                            // 计算偏航角
                            double yawDelta = caculateYawDelta(xAxisData, yAxisData, zAxisData);
                            double acceleration = caculateAccelerationDelta(xAxisData, yAxisData, zAxisData);
//                            LogUtils.d(SensorConstant.kAccelerometerLogTag, "yawDelta = %1s, accelerationDelta = %2s", yawDelta, acceleration);
//                            LogUtils.local(SensorConstant.kAccelerometerLogTag, "yawDelta = %1s, accelerationDelta = %2s", yawDelta, acceleration);

                            final MotionDeltaBean deltaBean = new MotionDeltaBean(acceleration, yawDelta);
                            Intent broadcastIntent = new Intent();
                            broadcastIntent.setAction(KDApp.mBroadcastSensorAction);
                            //broadcastIntent.putExtra("Data", "Broadcast Data");
                            broadcastIntent.putExtra("Data", deltaBean);
                            mContext.sendBroadcast(broadcastIntent);

                            //ThreadUtils.runOnMainThreadAsync(new Runnable() {
                            //    @Override
                            //    public void run() {
                            //        EventBusManager.getInstance().post(new MotionDeltaEvent(deltaBean));
                            //    }
                            //});
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            else if (sensorType == SensorUtils.SENSOR_TYPE_GYROSCOPE) {
                if (data != null) {
                    try {
                        GyroscopeFormatter formatter = (GyroscopeFormatter) DataFormatter.getJSONFormatter(mContext, SensorUtils.SENSOR_TYPE_GYROSCOPE);
                        if (formatter != null) {
                            String jsonData = formatter.toString(data);
                            String content = String.format("%1s\n\n", jsonData);
                            LogUtils.local(SensorConstant.kGyroscopeLogTag, content);

                            JSONObject jsonObject = new JSONObject(jsonData);
                            JSONArray xAxis = jsonObject.optJSONArray("xAxis");
                            JSONArray yAxis = jsonObject.optJSONArray("yAxis");
                            JSONArray zAxis = jsonObject.optJSONArray("zAxis");
                            double[] xAxisData = new double[xAxis.length()];
                            for (int i = 0; i < xAxis.length(); i++) {
                                xAxisData[i] = xAxis.optDouble(i);
                            }

                            double[] yAxisData = new double[yAxis.length()];
                            for (int i = 0; i < yAxis.length(); i++) {
                                yAxisData[i] = yAxis.optDouble(i);
                            }

                            double[] zAxisData = new double[zAxis.length()];
                            for (int i = 0; i < zAxis.length(); i++) {
                                zAxisData[i] = zAxis.optDouble(i);
                            }

                            final double accelerationDelta = caculateAccelerationDelta(xAxisData, yAxisData, zAxisData);
//                            ThreadUtils.runOnMainThreadAsync(new Runnable() {
//                                @Override
//                                public void run() {
//                                    EventBusManager.getInstance().post(new GyroscopeEvent(accelerationDelta));
//                                }
//                            });
//                            LogUtils.d("Test", "acceslerometer threshold = %s", SensorConstant.kAccelerationThreshold);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            else if (sensorType == SensorUtils.SENSOR_TYPE_MAGNETIC_FIELD) {
                MagneticFieldFormatter formatter = (MagneticFieldFormatter) DataFormatter.getJSONFormatter(mContext, SensorUtils.SENSOR_TYPE_MAGNETIC_FIELD);
                if (formatter != null) {
                    String jsonData = formatter.toString(data);
                    String content = String.format("%1s\n\n", jsonData);
                    LogUtils.local(SensorConstant.kMagneticFieldLogTag, content);
                }
            }
            else if (sensorType == SensorUtils.SENSOR_TYPE_PROXIMITY) {
                ProximityFormatter formatter = (ProximityFormatter) DataFormatter.getJSONFormatter(mContext, SensorUtils.SENSOR_TYPE_PROXIMITY);
                if (formatter != null) {
                    String jsonData = formatter.toString(data);
                    String content = String.format("%1s\n\n", jsonData);
                    LogUtils.local(SensorConstant.kProximityLogTag, content);
                }
            }
            else if (sensorType == SensorUtils.SENSOR_TYPE_STEP_COUNTER) {
                StepCounterFormatter formatter = (StepCounterFormatter) DataFormatter.getJSONFormatter(mContext, SensorUtils.SENSOR_TYPE_STEP_COUNTER);
                if (formatter != null) {
                    String jsonData = formatter.toString(data);
                    String content = String.format("%1s\n\n", jsonData);
                    LogUtils.local(SensorConstant.kStepCounterLogTag, content);
                }
            }
            else if (sensorType == SensorUtils.SENSOR_TYPE_PASSIVE_LOCATION) {
                PassiveLocationFormatter formatter = (PassiveLocationFormatter) DataFormatter.getJSONFormatter(mContext, SensorUtils.SENSOR_TYPE_PASSIVE_LOCATION);
                if (formatter != null) {
                    String jsonData = formatter.toString(data);
                    String content = String.format("%1s\n\n", jsonData);
                    LogUtils.local(SensorConstant.kPassiveLocationLogTag, content);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            ToastUtil.getInstance().showToast(e.getLocalizedMessage());
        }
    }

    private static double caculateAccelerationDelta(double[] xAxisData, double[] yAxisData, double[] zAxisData) {
        double[] accelerationData = new double[xAxisData.length];
        double min = 0.0f;
        double max = 0.0f;
        for (int i = 0; i < accelerationData.length; i++) {
            accelerationData[i] = Math.sqrt(0.1*Math.pow(xAxisData[i], 2) + 0.1*Math.pow(yAxisData[i], 2) + 0.8*Math.pow(zAxisData[i], 2));

//            accelerationData[i] = Math.sqrt(Math.pow(yAxisData[i], 2) + Math.pow(zAxisData[i], 2));
            if (i == 0) {
                min = Math.abs(accelerationData[i]);
                max = Math.abs(accelerationData[i]);
            }
            if (Double.compare(accelerationData[i], min) < 0) {
                min = Math.abs(accelerationData[i]);
            }

            if (Double.compare(accelerationData[i], max) > 0) {
                max = Math.abs(accelerationData[i]);
            }
        }
        return Math.abs(max - min);
    }


//    private static double caculateAccelerationDelta(double[] xAxisData, double[] yAxisData, double[] zAxisData) {
//        double[] accelerationData = new double[xAxisData.length];
//        double min = 0.0f;
//        double max = 0.0f;
//        for (int i = 0; i < accelerationData.length; i++) {
//            accelerationData[i] = Math.sqrt(Math.pow(xAxisData[i], 2) + Math.pow(yAxisData[i], 2) + Math.pow(zAxisData[i], 2));
//            if (i == 0) {
//                min = Math.abs(accelerationData[i]);
//                max = Math.abs(accelerationData[i]);
//            }
//            if (Double.compare(accelerationData[i], min) < 0) {
//                min = Math.abs(accelerationData[i]);
//            }
//
//            if (Double.compare(accelerationData[i], max) > 0) {
//                max = Math.abs(accelerationData[i]);
//            }
//        }
//        return Math.abs(max - min);
//    }

    /*
    void loop()
{
    double pitch, roll, Xg, Yg, Zg;
    acc.read(&Xg, &Yg, &Zg);

    //Low Pass Filter
    fXg = Xg * alpha + (fXg * (1.0 - alpha));
    fYg = Yg * alpha + (fYg * (1.0 - alpha));
    fZg = Zg * alpha + (fZg * (1.0 - alpha));

    //Roll & Pitch Equations
    roll  = (atan2(-fYg, fZg)*180.0)/M_PI;
    pitch = (atan2(fXg, sqrt(fYg*fYg + fZg*fZg))*180.0)/M_PI;

    Serial.print(pitch);
    Serial.print(":");
    Serial.println(roll);

    delay(10);
}
     */

//    private static double caculateYawDelta(double[] xAxisData, double[] yAxisData, double[] zAxisData) {
//        // 计算偏航角
//        // yaw = 180 * atan (accelerationZ/sqrt(accelerationX*accelerationX + accelerationZ*accelerationZ))/M_PI;
////        roll  = (atan2(-fYg, fZg)*180.0)/M_PI;
//
//
//        double[] yawData = new double[xAxisData.length];
//        double min = 0.0f;
//        double max = 0.0f;
//        for (int i = 0; i < yawData.length; i++) {
////            yawData[i] = (180*Math.atan2(zAxisData[i], (Math.pow(xAxisData[i], 2) + Math.pow(zAxisData[i], 2))))/Math.PI;
//            yawData[i] = (180*Math.atan2(-yAxisData[i], zAxisData[i]))/Math.PI;
//
//            if (i == 0) {
//                min = Math.abs(yawData[i]);
//                max = Math.abs(yawData[i]);
//            }
//            if (Double.compare(yawData[i], min) < 0) {
//                min = Math.abs(yawData[i]);
//            }
//
//            if (Double.compare(yawData[i], max) > 0) {
//                max = Math.abs(yawData[i]);
//            }
//        }
//        return Math.abs(max - min);
//    }

    // http://code.tutsplus.com/tutorials/using-the-accelerometer-on-android--mobile-22125
    // 用坐标轴权重的方式来处理，需要寻求更好的方式

    private static double caculateYawDelta(double[] xAxisData, double[] yAxisData, double[] zAxisData) {
        // 计算偏航角
        // yaw = 180 * atan (accelerationZ/sqrt(accelerationX*accelerationX + accelerationZ*accelerationZ))/M_PI;
//        roll  = (atan2(-fYg, fZg)*180.0)/M_PI;


        double[] yawData = new double[xAxisData.length];
        double min = 0.0f;
        double max = 0.0f;
        for (int i = 0; i < yawData.length; i++) {
//            yawData[i] = (180*Math.atan2(zAxisData[i], (Math.pow(xAxisData[i], 2) + Math.pow(zAxisData[i], 2))))/Math.PI;
//            yawData[i] = (180*Math.atan2(-yAxisData[i], zAxisData[i]))/Math.PI;
//            yawData[i] = Math.sqrt(Math.pow(xAxisData[i], 2) + Math.pow(zAxisData[i], 2));
            yawData[i] = Math.sqrt(0.1*Math.pow(xAxisData[i], 2) + 0.8*Math.pow(yAxisData[i], 2) + 0.1*Math.pow(zAxisData[i], 2));


            if (i == 0) {
                min = Math.abs(yawData[i]);
                max = Math.abs(yawData[i]);
            }
            if (Double.compare(yawData[i], min) < 0) {
                min = Math.abs(yawData[i]);
            }

            if (Double.compare(yawData[i], max) > 0) {
                max = Math.abs(yawData[i]);
            }
        }
        return Math.abs(max - min);
    }



    @Override
    public void onCrossingLowBatteryThreshold(boolean isBelowThreshold) {
        // TODO: what happens when there is low battery?
        if (stop) return;
        LogUtils.d("onCrossingLowBatteryThreshold");
    }
}
